#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#       odsPassword.py - Mestrado em Engenharia de Segurança Informática
#       
#       Copyright 2013 Mário Candeias <198912832@alunos.ipbeja.pt>
#       
#       This program is an academic software.
#       Only for academic purposes. Under free GNU Licences.
# #http://docs.python.org/2/library/zipfile

#coding: utf8
import sys
import os
import zipfile
from xml.etree.ElementTree import ElementTree

class MyOutput():
################################################
### Necessary to print for file and stdout   ###
### at the same time.                        ###
################################################
    def __init__(self, logfile):
        self.stdout = sys.stdout
        self.log = open(logfile, 'w')
 
    def write(self, text):
        self.stdout.write(text)
        self.log.write(text)
        self.log.flush()
 
    def close(self):
        self.stdout.close()
        self.log.close()
        
def fileContents(odsFile, filename):
######################################################################
### The ODF file is basicly un zip file. This method open the ODF, ###
### Show all structure contents and save them on a text file.      ###
######################################################################
    TextFileName = "%s.txt" % os.path.splitext(filename)[0]
    sys.stdout = MyOutput(TextFileName)
    try:
        print "--- File  %s  was opened ---" % (sys.argv[1])
        listoffiles = odsFile.infolist()
#        print "\n--- listoffiles --------->\n\n%s\n\n<--------\n" % (listoffiles)

        print ("\n  [--------------Contents of File------------ + -----Date & Time of last---- + -Uncompressed- + -Header- + --CRC 32 bit--]")
        print ("\n  [-------------------(path)----------------- + -modification (Y,M,D,h,m,s)- + --file size--- + -Offset- + -Uncomp. file-]\n")
        for i in listoffiles:
            ptext = "[-] %40s  +  %26s  +  %12s  +  %7s  +  %7s" % (i.filename, i.date_time, i.file_size, i.header_offset, i.CRC)
            print ptext
        print "\n--- Output was created with the name %s" % TextFileName
        print "\n####################################################################################"

        return TextFileName

    except Exception, e:
        print "[-] " + str(e)
        sys.exit()

def getElements(TextFileName, odsFile):
################################################
### Open the file manifest.xml and parse     ###
### all necessary elements.                  ###
################################################
    try:
        manifest = odsFile.open("META-INF/manifest.xml")
    except KeyError, exc:
        print >> sys.stderr, "\n %s is not an OpenOffice file! --- The program finished!" % sys.argv[1]
        sys.exit()

    tree = ElementTree()
    tree.parse(manifest)
    root = tree.getroot()
    elements = list(root.getiterator())
    encryptedFile = False
    key_size = 16
    for i in range(0, len(elements)):
        element = elements[i]
        if element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}full-path") == "content.xml":
            elementsIfCrypt = element.items()
            for j in range(i + 1, i + 1 + 3):
                element = elements[j]
                elementsIfCrypt += element.items()
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}checksum")
                if data:
                    checksum = data
                    encryptedFile = True
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}checksum-type")
                if data:
                    checksum_type = data
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}initialisation-vector")
                if data:
                    iv = data
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}salt")
                if data:
                    salt = data
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}algorithm-name")
                if data:
                    algorithm_name = data
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}iteration-count")
                if data:
                    iteration_count = data
                data = element.get("{urn:oasis:names:tc:opendocument:xmlns:manifest:1.0}key-size")
                if data:
                    key_size = data
                    elementsIfCrypt += element.items()
    
    if encryptedFile:
        outputElements(checksum, checksum_type, iv, salt, algorithm_name, iteration_count, key_size, TextFileName)
        sys.stdout = sys.__stdout__
        outputRawFile(elementsIfCrypt, TextFileName)
    else:
        sys.stdout = MyOutput(TextFileName)
        print "--- The file is not an encrypted File! --- \n   --- The program finished ---"
        sys.exit()
        sys.stdout = sys.__stdout__
    return checksum, checksum_type, iv, salt, algorithm_name, iteration_count, key_size, TextFileName

def outputElements(checksum, checksum_type, iv, salt, algorithm_name, iteration_count, key_size, TextFileName):
###################################################################
### Displays the crypt information and saves it to a text file. ###
###################################################################
    print "   ---  Crypt informations of content.xml file ---"
    print "\nchecksum = %s \ninitialisation-vector = %s \nSalt = %s \nchecksum type = %s \nalgorithm-name = %s \niteration-count = %s \n"% (checksum, iv, salt, checksum_type, algorithm_name, iteration_count)
    print "\n --- This information was saved %s file. --- " % TextFileName
    print "\n####################################################################################\n"
    sys.stdout = sys.__stdout__

def outputRawFile(elements, TextFileName):
################################################
### Save Contents in a output RAW file.      ###
################################################
    rawFileName = "%s.od_" % os.path.splitext(TextFileName)[0]
    print " --- The raw elements of content.xml file ---\n"
    sys.stdout = MyOutput(rawFileName)
    print "%s" % elements
    sys.stdout = sys.__stdout__
    print "\nThe raw file it was created with name: %s" % rawFileName
    return rawFileName

def main():
    if len(sys.argv) < 2:
        print >> sys.stderr, "Usage: %s <ODS file>" % sys.argv[0]
        sys.exit(1)
    try:
        odsFile = zipfile.ZipFile(sys.argv[1])
    except zipfile.BadZipfile:
        print >> sys.stderr, "\n %s is not an OpenOffice file! --- The program finished!" % sys.argv[1]
        sys.exit(2)


    TextFileName = fileContents(odsFile, sys.argv[1]) #---Open ODF file, show structure and save them on a text file

    checksum, checksum_type, iv, salt, algorithm_name, iteration_count, key_size, TextFileName = getElements(TextFileName, odsFile)

    print "\n --- The program finished! ---"

    odsFile.close()
    
if __name__ == '__main__':
    main()
